/*
 * Copyright (c) 2018-2999 北京小象智慧信息科技有限公司 All rights reserved.
 *
 * https://www.xiaoxiangai.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.yami.shop.bean.app.dto.*;
import com.yami.shop.bean.app.param.ChangeShopCartParam;
import com.yami.shop.bean.app.param.OrderItemParam;
import com.yami.shop.bean.app.param.ShopCartParam;
import com.yami.shop.bean.event.ShopCartEvent;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.pt.YxPtsp;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.CacheManagerUtil;
import com.yami.shop.dao.BasketMapper;
import com.yami.shop.service.*;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lgh on 2018/10/18.
 */
@Service
@AllArgsConstructor
@Transactional
public class BasketServiceImpl extends ServiceImpl<BasketMapper, Basket> implements BasketService {

    private final BasketMapper basketMapper;

    private final CacheManagerUtil cacheManagerUtil;

    private final ApplicationContext applicationContext;

    private final SkuService skuService;

    private final ShopDetailService shopDetailService;

    private final ProductService productService;

    private final CouponService couponService;

    private final ActivityService activityService;

    private final IYxPtspService iYxPtspService;


    @Override
    @CacheEvict(cacheNames = "ShopCartItems", key = "#userId")
    public void deleteShopCartItemsByBasketIds(String userId, List<Long> basketIds) {
        basketMapper.deleteShopCartItemsByBasketIds(userId, basketIds);
    }

    @Override
    @CacheEvict(cacheNames = "ShopCartItems", key = "#userId")
    public void addShopCartItem(ChangeShopCartParam param, String userId) {
        Basket basket = new Basket();
        basket.setBasketCount(param.getCount());
        basket.setBasketDate(new Date());
        basket.setProdId(param.getProdId());
        basket.setShopId(param.getShopId());
        basket.setUserId(userId);
        basket.setSkuId(param.getSkuId());
        basket.setDistributionCardNo(param.getDistributionCardNo());
        basketMapper.insert(basket);
    }

    @Override
    @CacheEvict(cacheNames = "ShopCartItems", key = "#basket.userId")
    public void updateShopCartItem(Basket basket) {
        basketMapper.updateById(basket);
    }

    @Override
    @CacheEvict(cacheNames = "ShopCartItems", key = "#userId")
    public void deleteAllShopCartItems(String userId) {
        basketMapper.deleteAllShopCartItems(userId);
    }

    @Override
    public List<ShopCartItemDto> getShopCartItems(String userId,Long shopId) {
        // 在这个类里面要调用这里的缓存信息，并没有使用aop，所以不使用注解
        List<ShopCartItemDto> shopCartItemDtoList = cacheManagerUtil.getCache("ShopCartItems", userId);
        shopCartItemDtoList = basketMapper.getShopCartItems(userId,shopId);
        for (ShopCartItemDto shopCartItemDto : shopCartItemDtoList) {
            Sku sku = skuService.getSkuBySkuId(shopCartItemDto.getSkuId());
            if (sku == null) {
                throw new RuntimeException("订单包含无法识别的商品");
            }
            Product prod = productService.getProductByProdId(shopCartItemDto.getProdId());
            if (prod == null) {
                throw new RuntimeException("订单包含无法识别的商品");
            }
            shopCartItemDto.setProductTotalAmount(Arith.mul(shopCartItemDto.getProdCount(), shopCartItemDto.getPrice()));
            // 用户优惠券列表
            int couponKind = 0;
            List<CouponDto> couponList = couponService.getAllCoupon(shopCartItemDto.getShopId(),shopCartItemDto.getProdId(),userId,couponKind);
            // 支付金额
            BigDecimal money = new BigDecimal(Arith.mul(sku.getPrice(),shopCartItemDto.getProdCount()));
            List<CouponDto> optimumList = null;
            if(couponList.size()>0){
                optimumList = getOptimumList(couponList, money);
            }
            if(optimumList!=null){
                shopCartItemDto.setDiscountMoney(optimumList.get(0).getFullAmountReduce());
                shopCartItemDto.setFavorablePrice(Arith.sub(money.doubleValue(),optimumList.get(0).getFullAmountReduce()));
                shopCartItemDto.setRecordId(optimumList.get(0).getRecordId());
                //查询商品有没有活动价格
                Product product = productService.getProductByProdId(shopCartItemDto.getProdId());
                Double activityPrice = product.getActivityPrice();
                Integer activityTimes = product.getActivityTimes();
                if(activityPrice!=null){
                    //查看当前时间在不在活动期间内
                    Product activityProd = productService.getActivityProd(shopCartItemDto.getProdId());
                    if(activityProd!=null){
                        shopCartItemDto.setActivityPrice(null);
                    }else{
                        Long acticityId = product.getActivityId();
                        ActivityPro activityPro = activityService.getById(acticityId);
                        shopCartItemDto.setActivityPrice(activityPrice);
                        if(activityPro!=null) {
                            shopCartItemDto.setActivityTimesFlag(activityPro.getActivityTimesFlag());
                            shopCartItemDto.setActivityOrderFlag(activityPro.getActivityOrderFlag());
                        }
                    }


                }
            }else {
                shopCartItemDto.setDiscountMoney(0.0);
                shopCartItemDto.setFavorablePrice(money.doubleValue());
                //查询商品有没有活动价格
                Product product = productService.getProductByProdId(shopCartItemDto.getProdId());
                Double activityPrice = product.getActivityPrice();
                Integer activityTimes = product.getActivityTimes();
                if(activityPrice!=null){
                    //查看当前时间在不在活动期间内
                    Product activityProd = productService.getActivityProd(shopCartItemDto.getProdId());
                    if(activityProd!=null){
                        shopCartItemDto.setActivityPrice(null);
                    }else{
                        Long acticityId = product.getActivityId();
                        ActivityPro activityPro = activityService.getById(acticityId);
                        shopCartItemDto.setActivityPrice(activityPrice);
                        if(activityPro!=null) {
                            shopCartItemDto.setActivityTimesFlag(activityPro.getActivityTimesFlag());
                            shopCartItemDto.setActivityOrderFlag(activityPro.getActivityOrderFlag());
                        }
                    }


                }
            }
        }
        cacheManagerUtil.putCache("ShopCartItems", userId, shopCartItemDtoList);
        return shopCartItemDtoList;
    }

    @Override
    public List<ShopCartItemDto> getShopCartExpiryItems(String userId) {
        return basketMapper.getShopCartExpiryItems(userId);
    }

    @Override
    @CacheEvict(cacheNames = "ShopCartItems", key = "#userId")
    public void cleanExpiryProdList(String userId) {
        basketMapper.cleanExpiryProdList(userId);
    }

    @Override
    @CacheEvict(cacheNames = "ShopCartItems", key = "#userId")
    public void updateBasketByShopCartParam(String userId, Map<Long, ShopCartParam> basketIdShopCartParamMap) {
        basketMapper.updateDiscountItemId(userId, basketIdShopCartParamMap);
    }

    @Override
    @CacheEvict(cacheNames = "ShopCartItems", key = "#userId")
    public void removeShopCartItemsCacheByUserId(String userId) {

    }

    @Override
    public List<String> listUserIdByProdId(Long prodId) {
        return basketMapper.listUserIdByProdId(prodId);
    }

    @Override
    public List<ShopCartDto> getShopCarts(List<ShopCartItemDto> shopCartItems) {
        // 根据店铺ID划分item
        Map<Long, List<ShopCartItemDto>> shopCartMap = shopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemDto::getShopId));

        // 返回一个店铺的所有信息
        List<ShopCartDto> shopCartDtos = Lists.newArrayList();
        for (Long shopId : shopCartMap.keySet()) {

            //获取店铺的所有商品项
            List<ShopCartItemDto> shopCartItemDtoList = shopCartMap.get(shopId);

            // 构建每个店铺的购物车信息
            ShopCartDto shopCart = new ShopCartDto();

            //店铺信息
            shopCart.setShopId(shopId);
            shopCart.setShopName(shopCartItemDtoList.get(0).getShopName());

            applicationContext.publishEvent(new ShopCartEvent(shopCart, shopCartItemDtoList));

            shopCartDtos.add(shopCart);
        }

        return shopCartDtos;
    }

    @Override
    public List<ShopCartItemDto> getShopCartItemsByOrderItems(List<Long> basketId, OrderItemParam orderItem,String userId,Long shopId) {
        if (orderItem == null && CollectionUtil.isEmpty(basketId)) {
            return Collections.emptyList();
        }
        // 当立即购买时，没有提交的订单是没有购物车信息的
        if (CollectionUtil.isEmpty(basketId) && orderItem != null) {
            //获取商品拼团价格
            YxPtsp yxPtsp =  iYxPtspService.getYxPtspbyProdId(orderItem.getProdId());
            BigDecimal ptj = new BigDecimal("0");
            if(yxPtsp!=null){
                ptj =  yxPtsp.getPtj();
            }
            String  purchaseType = orderItem.getPurchaseType();
            Sku sku = skuService.getSkuBySkuId(orderItem.getSkuId());
            if (sku == null) {
                throw new RuntimeException("订单包含无法识别的商品");
            }
            Product prod = productService.getProductByProdId(orderItem.getProdId());
            if (prod == null) {
                throw new RuntimeException("订单包含无法识别的商品");
            }

            // 单品优惠券列表
            int couponKind = 0;
            List<CouponDto> couponList = couponService.getAllCoupon(orderItem.getShopId(),orderItem.getProdId(),userId,couponKind);
            // 支付金额
            BigDecimal money = new BigDecimal("0");
            if(purchaseType.equals("1")) {
                 money = new BigDecimal(Arith.mul(sku.getPrice(), orderItem.getProdCount()));
            }else if(purchaseType.equals("2")){
                 money = new BigDecimal(Arith.mul(Double.valueOf(ptj.toString()), orderItem.getProdCount()));
            }
            List<CouponDto> optimumList = null;
            if(couponList.size()>0){
                optimumList = getOptimumList(couponList, money);
            }

            // 拿到购物车的所有item
            ShopCartItemDto shopCartItemDto = new ShopCartItemDto();
            shopCartItemDto.setBasketId(-1L);
            shopCartItemDto.setSkuId(orderItem.getSkuId());
            shopCartItemDto.setProdCount(orderItem.getProdCount());
            shopCartItemDto.setProdId(orderItem.getProdId());
            shopCartItemDto.setSkuName(sku.getSkuName());
            shopCartItemDto.setPic(StrUtil.isBlank(sku.getPic())? prod.getPic() : sku.getPic());
            shopCartItemDto.setProdName(sku.getProdName());
            shopCartItemDto.setProductTotalAmount(Arith.mul(sku.getPrice(),orderItem.getProdCount()));
            shopCartItemDto.setPrice(sku.getPrice());
           // shopCartItemDto.setDistributionCardNo(orderItem.getDistributionCardNo());
            shopCartItemDto.setBasketDate(new Date());
            ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(orderItem.getShopId());
            shopCartItemDto.setShopId(shopDetail.getShopId());
            shopCartItemDto.setShopName(shopDetail.getShopName());
            if(optimumList!=null){
                double reduceMoney = optimumList.get(0).getFullAmountReduce();
                BigDecimal data1 = new BigDecimal(reduceMoney);
                if(data1.compareTo(money)>0){
                    shopCartItemDto.setDiscountMoney(0.0);
                    shopCartItemDto.setFavorablePrice(money.doubleValue());
                }else {
                    shopCartItemDto.setDiscountMoney(optimumList.get(0).getFullAmountReduce());
                    shopCartItemDto.setFavorablePrice(Arith.sub(money.doubleValue(), optimumList.get(0).getFullAmountReduce()));
                    shopCartItemDto.setRecordId(optimumList.get(0).getRecordId());
                }
            }else {
                shopCartItemDto.setDiscountMoney(0.0);
                shopCartItemDto.setFavorablePrice(money.doubleValue());
            }
            return Collections.singletonList(shopCartItemDto);
        }
        List<ShopCartItemDto> dbShopCartItems = getShopCartItems(userId,shopId);

        // 返回购物车选择的商品信息
        return dbShopCartItems
                .stream()
                .filter(shopCartItemDto -> basketId.contains(shopCartItemDto.getBasketId()))
                .collect(Collectors.toList());
    }

    @Override
    public List<ShopCartItemDto> getShopCartItemsByBuyAgain(OrderItemParam orderItem, String userId, Long shopId) {
        if (orderItem == null) {
            return Collections.emptyList();
        }
        Sku sku = skuService.getSkuBySkuId(orderItem.getSkuId());
        if (sku == null) {
            throw new RuntimeException("订单包含无法识别的商品");
        }
        Product prod = productService.getProductByProdId(orderItem.getProdId());
        if (prod == null) {
            throw new RuntimeException("订单包含无法识别的商品");
        }

        // 单品优惠券列表
        int couponKind = 0;
        List<CouponDto> couponList = couponService.getAllCoupon(orderItem.getShopId(),orderItem.getProdId(),userId,couponKind);
        // 支付金额
        BigDecimal money = new BigDecimal(Arith.mul(sku.getPrice(),orderItem.getProdCount()));
        List<CouponDto> optimumList = null;
        if(couponList.size()>0){
            optimumList = getOptimumList(couponList, money);
        }

        // 拿到购物车的所有item
        ShopCartItemDto shopCartItemDto = new ShopCartItemDto();
        shopCartItemDto.setBasketId(-1L);
        shopCartItemDto.setSkuId(orderItem.getSkuId());
        shopCartItemDto.setProdCount(orderItem.getProdCount());
        shopCartItemDto.setProdId(orderItem.getProdId());
        shopCartItemDto.setSkuName(sku.getSkuName());
        shopCartItemDto.setPic(StrUtil.isBlank(sku.getPic())? prod.getPic() : sku.getPic());
        shopCartItemDto.setProdName(sku.getProdName());
        shopCartItemDto.setProductTotalAmount(Arith.mul(sku.getPrice(),orderItem.getProdCount()));
        shopCartItemDto.setPrice(sku.getPrice());
       // shopCartItemDto.setDistributionCardNo(orderItem.getDistributionCardNo());
        shopCartItemDto.setBasketDate(new Date());
        ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(orderItem.getShopId());
        shopCartItemDto.setShopId(shopDetail.getShopId());
        shopCartItemDto.setShopName(shopDetail.getShopName());
        if(optimumList!=null){
            double reduceMoney = optimumList.get(0).getFullAmountReduce();
            BigDecimal data1 = new BigDecimal(reduceMoney);
            if(data1.compareTo(money)>0){
                shopCartItemDto.setDiscountMoney(0.0);
                shopCartItemDto.setFavorablePrice(money.doubleValue());
            }else {
                shopCartItemDto.setDiscountMoney(optimumList.get(0).getFullAmountReduce());
                shopCartItemDto.setFavorablePrice(Arith.sub(money.doubleValue(), optimumList.get(0).getFullAmountReduce()));
                shopCartItemDto.setRecordId(optimumList.get(0).getRecordId());
            }
        }else {
            shopCartItemDto.setDiscountMoney(0.0);
            shopCartItemDto.setFavorablePrice(money.doubleValue());
        }
        return Collections.singletonList(shopCartItemDto);
    }

    @Override
    public Basket getBasketByProdId(Basket basket) {
        return basketMapper.getBasketByProdId(basket);
    }

    public List<CouponDto> getOptimumList(List<CouponDto> couponList, BigDecimal amount) {
        // 无门槛代金券集合
        List<CouponDto> voucherList = new ArrayList<>();
        // 满减券集合
        List<CouponDto> discountList = new ArrayList<>();
        for (CouponDto couponDto : couponList) {
            /**
             * 满减金额
             */
            BigDecimal reduceMoney = null;
            if(couponDto.getCouponType()==1){
                reduceMoney = new BigDecimal(couponDto.getReduceMoney());
            }
            /**
             * 优惠券金额
             */
            BigDecimal fullReduceMoney = new BigDecimal(couponDto.getFullAmountReduce());
            //付款金额大于优惠券金额时，优惠券有效
            if (couponDto.getCouponType()==0&& amount.compareTo(fullReduceMoney)>=0) {
                voucherList.add(couponDto);
            }
            //付款金额达到满减金额时有效
            if (couponDto.getCouponType()==1&& amount.compareTo(reduceMoney)>=0) {
                discountList.add(couponDto);
            }
        }
        // endResultMap 同批次现金券最优解，折扣券最优解，代金券最优解
        // endResultMap key 优惠券id字符串 value 最优解优惠金额
        HashMap<String, Integer> endResultMap = new HashMap<>();

        // 代金券处理开始 判断长度
        if (voucherList.size() > 0) {
            voucherList.sort((CouponDto c1, CouponDto c2) -> c1.getFullAmountReduce().compareTo(c2.getFullAmountReduce()));
            // 获取代金券最大值，放入最终结果map
            endResultMap.put(voucherList.get(voucherList.size() - 1).getCouponId() + "",-
                    voucherList.get(voucherList.size() - 1).getFullAmountReduce().intValue());
            // 代金券处理结束
        }
        // 折扣券处理开始 判断长度
//        if (discountList.size() > 0) {
//            discountList.sort((Coupon c1, Coupon c2) -> c1.getFullAmountReduce().compareTo(c2.getFullAmountReduce()));
//            // 获取折扣最小值 并计算最大折扣金额
//            BigDecimal discountTmp = new BigDecimal(discountList.get(0).getFullAmountReduce());
//            BigDecimal realCountTmp = new BigDecimal(100).subtract(discountTmp);
//            BigDecimal discountTmpVal = amount.multiply(realCountTmp).divide(new BigDecimal(100));
//            endResultMap.put(discountList.get(0).getCouponId() + "", discountTmpVal.intValue());
//            // 折扣券处理结束
//        }
        if (discountList.size() > 0) {
            discountList.sort((CouponDto c1, CouponDto c2) -> c1.getFullAmountReduce().compareTo(c2.getFullAmountReduce()));
            // 获取满减最小值 并计算最大满减金额
            endResultMap.put(discountList.get(discountList.size()-1).getCouponId() + "", -discountList.get(discountList.size()-1).getFullAmountReduce().intValue());
            // 满减券处理结束
        }
        if(voucherList.size()<=0&&discountList.size()<=0){
            return null;
        }
        // 获取最终结果
        int endResult = getOptimumVal4Map(endResultMap, amount);
        // 获取优惠券id集合字符串
        String couponDetailStr = getOptimumStr(endResultMap, endResult);
        // 判断是否为空
        List<String> couponDetailIdList = new ArrayList<>();
        if (StringUtils.isNotEmpty(couponDetailStr)) {
            if (couponDetailStr.contains("-")) {
                String[] couponDetailArr = couponDetailStr.split("-");
                for (String str : couponDetailArr) {
                    couponDetailIdList.add(str);
                }
            } else {
                couponDetailIdList.add(couponDetailStr);
            }
        }
        List<CouponDto> optimumList = new ArrayList<>();
        // 循环用户优惠券列表，进行比较
        for (CouponDto couponDto : couponList) {
            for (String str : couponDetailIdList) {
                if (couponDto.getCouponId() == Integer.parseInt(str)) {
                    optimumList.add(couponDto);
                }
            }
        }
        return optimumList;
    }

    private static int getOptimumVal4Map(HashMap<String, Integer> map, BigDecimal amount) {
        ArrayList<Integer> array = new ArrayList<Integer>();
        ArrayList<Integer> array1 = new ArrayList<Integer>();
        for (Map.Entry<String, Integer> m2 : map.entrySet()) {
            array1.add(m2.getValue());
        }
        array.add(Collections.min(array1));
        int result = binarysearchKey(array.toArray(), amount);
        return result;
    }

    private static String getOptimumStr(HashMap<String, Integer> map, int result) {
        for (Map.Entry<String, Integer> m : map.entrySet()) {
            if (m.getValue().intValue() == result) {
                return m.getKey();
            }
        }
        return null;
    }

    // 筛选最接近支付金额的结果
    public static int binarysearchKey(Object[] array, BigDecimal targetNum) {
        Arrays.sort(array);
        int left = 0, right = 0;
        for (right = array.length - 1; left != right; ) {
            int midIndex = (right + left) / 2;
            int mid = (right - left);
            int midValue = (Integer) array[midIndex];
            if (targetNum.compareTo(new BigDecimal(midValue)) == 0) {
                return midValue;
            }

            if (targetNum.compareTo(new BigDecimal(midValue)) == 1) {
                left = midIndex;
            } else {
                right = midIndex;
            }
            if (mid <= 1) {
                break;
            }
        }
        int rightnum = ((Integer) array[right]).intValue();
        int leftnum = ((Integer) array[left]).intValue();
        // 如果一个大于支付金额，一个小于支付金额，优先返回大于支付金额的结果
        if (new BigDecimal(rightnum).compareTo(targetNum) == 1 && new BigDecimal(leftnum).compareTo(targetNum) == -1) {
            return rightnum;
        }
        BigDecimal rightiffVal = new BigDecimal(rightnum).subtract(targetNum);
        BigDecimal leftDiffVal = new BigDecimal(leftnum).subtract(targetNum);
        int ret = Math.abs(leftDiffVal.intValue()) > Math.abs(rightiffVal.intValue()) ? rightnum : leftnum;
        // System.out.println("要查找的数：" + targetNum + "最接近的数：" + ret);
        return ret;
    }

}
